package {
	import Box2D.Collision.*;
	import Box2D.Collision.Shapes.*;
	import Box2D.Common.Math.*;
	import Box2D.Dynamics.*;
	
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.TimerEvent;
	import flash.utils.Timer;
	
	public class PhysicsWorld extends Sprite {
		
		private var world:b2World;
		private var _worldReadyForStepping:Boolean = true;
		
		public function PhysicsWorld():void 
		{
		
			createWorld();
			
			drawDebug();		
			drawGround();
			drawBuilding();
			drawMeteor();
		
			//takeOneWorldStep();
		
			addEventListener(Event.ENTER_FRAME, enterFrameHandler);
			
			//timeCount.addEventListener(TimerEvent.TIMER, timeHandler);
			//timeCount.start();
		}
		
		private function createWorld():void
		{
				// create the enviroment 
			
			var environment:b2AABB = new b2AABB();
			environment.lowerBound.Set(-100.0, -100.0);
			environment.upperBound.Set(100.0, 100.0);
			
			// create the gravity
			
			var gravity:b2Vec2=new b2Vec2(0.0,10.0);
			
			// init the world
			
			world = new b2World(environment, gravity, true);
		}
		
		// until we have graphics, we need to see the objects
		private function drawDebug():void
		{
			var viewHiddenDebugDraw:b2DebugDraw = new b2DebugDraw();
			var viewHiddenPhysicsSprite:Sprite = new Sprite();
			
			addChild(viewHiddenPhysicsSprite);
			
			viewHiddenDebugDraw.m_sprite = viewHiddenPhysicsSprite;
			viewHiddenDebugDraw.m_drawScale=45; // 0 - 100 -- 100 is way too big
			viewHiddenDebugDraw.m_fillAlpha=0.5;
			viewHiddenDebugDraw.m_lineThickness=1;
			viewHiddenDebugDraw.m_drawFlags = b2DebugDraw.e_shapeBit; // ?? not sure but its necessary to see stuff
			
			world.SetDebugDraw(viewHiddenDebugDraw);
		}
		
		private function drawGround():void
		{
			var groundBody:b2Body; // not initiated
									
			var groundBodyDef:b2BodyDef = new b2BodyDef();
			groundBodyDef.position.Set(8.5, 13);
			
			var groundBox:b2PolygonDef = new b2PolygonDef();
			
			var groundBoxHX:Number = 8.3 // makes it just visible in the available space
			var groundBoxHY:Number = 0.5;
			
			groundBox.SetAsBox( groundBoxHX, groundBoxHY);
			groundBox.friction=0.3;
			groundBox.density=0;  /// anything more like 0.5 will make it start to fall
			
			groundBody = world.CreateBody(groundBodyDef);
			groundBody.CreateShape(groundBox);
			groundBody.SetMassFromShapes();
		}
		
		private function drawBuilding():void
		{
						
			/*
			 at first, I tried to draw the complete tower and got quite the mess of boxes
			 but by going block by block like:
			
			draw 1 block
			
			 var totalBuildingColumn:Number = 1;
			 var totalBuildingRow:Number = 1;
			 
			 draw 2 rows  
			
			 var totalBuildingColumn:Number = 1;
			 var totalBuildingRow:Number = 2;
			 
			 I was able to build the tower from the ground up and see the problems per floor 
			
			*/ 
			
			var totalBuildingColumn:Number = 4;
			var totalBuildingRow:Number = 6;
			
			for ( var columnCounter:Number = 0; columnCounter < totalBuildingColumn; columnCounter++ )
			{
				for ( var rowCounter:Number = 0; rowCounter < totalBuildingRow; rowCounter++ )
				{
					var buidlingBlock:b2Body;
					var buidlingBlockDef:b2BodyDef;
					var buidlingBlockBox:b2PolygonDef;
					
					buidlingBlockDef = new b2BodyDef();
										
					// position from ground up 
					var startX:Number = 10 + ( 0.9 * columnCounter ); // I assumed at first it would be 0.5 but I get an overlap; 0.9 removes the overlap
					var startY:Number = 12 - ( 1 * rowCounter ); // 12 was a trial and error ; 0.5 gives overlap
					
					buidlingBlockDef.position.Set(startX, startY);
					
					buidlingBlockBox = new b2PolygonDef();
					buidlingBlockBox.SetAsBox(0.5,0.5);
					
					// consider random building sizes
					// buidlingBlockBox.SetAsBox(Math.random()+0.1,Math.random()+0.1);
					
					buidlingBlockBox.friction=5;
					buidlingBlockBox.density=1;
					
					buidlingBlock = world.CreateBody(buidlingBlockDef);
					buidlingBlock.CreateShape(buidlingBlockBox);
					buidlingBlock.SetMassFromShapes();
				}
			}
			
			
		}
				
		private function drawMeteor():void
		{
			
			var meteorBallBody:b2Body;
			var meteorBallBodyDef:b2BodyDef;
			var meteorBallCircleDef:b2CircleDef;
					
			meteorBallBodyDef = new b2BodyDef();
										
			var startX:Number = 11.5; 
			var startY:Number = 2; 
					
			meteorBallBodyDef.position.Set(startX, startY);
					
			meteorBallCircleDef = new b2CircleDef();
			meteorBallCircleDef.radius = 0.5;
			meteorBallCircleDef.friction=5;
			meteorBallCircleDef.density=100; // 10 does nothing
					
			meteorBallBody = world.CreateBody(meteorBallBodyDef);
			meteorBallBody.CreateShape(meteorBallCircleDef);
			meteorBallBody.SetMassFromShapes();
			
			
		}
				
		
		private function takeOneWorldStep():void
		{
			world.Step(1/40, 50); 
			
			// the world gets more unstable as go from 1/50 to 1/20 
			// the second number seems to deal with hit detection moving 10 to 50 increased the reaction time from 10 to 1 sec.
		}
		
		private function enterFrameHandler(e:Event):void 
		{
			
			if ( _worldReadyForStepping ) 
			{
				takeOneWorldStep();
			}
			
		}
	}
}